package com.safframework.server.core

import com.safframework.server.core.converter.ConverterManager
import com.safframework.server.core.handler.socket.WebSocketListener
import com.safframework.server.core.handler.udp.UdpServerInitializer
import com.safframework.server.core.http.HttpMethod
import com.safframework.server.core.http.filter.HttpFilter
import com.safframework.server.core.log.LogManager
import com.safframework.server.core.ssl.SslContextFactory
import io.netty.bootstrap.Bootstrap
import io.netty.channel.ChannelFuture
import io.netty.channel.ChannelOption
import io.netty.channel.EventLoopGroup
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioDatagramChannel
import io.netty.handler.ssl.SslContext
import java.net.UnknownHostException

class UdpServer constructor(private val builder: ServerBuilder) : Server {

    private var sslContext: SslContext? = null

    private lateinit var bossGroup: EventLoopGroup

    private var channelFuture: ChannelFuture? = null

    init {
        builder.logProxy?.let { LogManager.logProxy(it) }

        builder.converter?.let { ConverterManager.converter(it) }

        if (builder.useTls) {
            sslContext = SslContextFactory.createSslContext()
        }
    }

    override fun start() {


        object : Thread() {
            override fun run() {

                val bootstrap = Bootstrap()
                bossGroup = NioEventLoopGroup(1)
                try {
                    bootstrap
                        .group(bossGroup)
                        .channel(NioDatagramChannel::class.java)
                        .localAddress(builder.address, builder.port)
                        .option(ChannelOption.SO_REUSEADDR, true)
                        .handler(UdpServerInitializer())
                    val cf = bootstrap.bind()
                    channelFuture = cf
                    cf.sync()
                    cf.channel().closeFuture().sync()
                } catch (e: UnknownHostException) {
                    throw RuntimeException(e)
                } catch (e: InterruptedException) {
                    throw RuntimeException(e)
                } finally {
                    close()
                }
            }
        }.start()

    }

    private fun isBossGroupInitialized() = ::bossGroup.isInitialized

    override fun close() {
        try {
            channelFuture?.channel()?.close()

            if (isBossGroupInitialized()) {
                bossGroup.shutdownGracefully()
            }
        } catch (e: InterruptedException) {
            LogManager.e(TAG, e.message ?: "error")
            throw RuntimeException(e)
        }
    }

    override fun request(method: HttpMethod, route: String, handler: RequestHandler): Server {
        return this
    }

    override fun filter(route: String, httpFilter: HttpFilter): Server {
        return this
    }

    override fun webSocket(webSocketPath: String?, listener: WebSocketListener<Any>): Server {

        return this
    }


    companion object {
        private const val TAG = "UdpServer"
    }
}